#include "EntityEnemy.h"
#include "WorldModel.h"
#include "ExplosionManager.h"
#include "ProjectileManager.h"
#include "Sound.h"
#include "Route.h"
#include "AI.h"

CEntityEnemy::CEntityEnemy(int /*currentPosX*/, int /*currentPosY*/, int indexSprite, int indexFrame, int /*speed*/, int health,
							 int collisionCost, int timeToSpawn, int timeToLive, int projectileType, bool active):
					totalHealth(health), timeSpawnLastProjectile(-1), timeBetweenProjectile(500),
					timeToSpawn(timeToSpawn), timeToLive(timeToLive), route(0), indexNextWayPoint(-1), 
					vectorNextWayPoint(CVector2D()), projectileType(projectileType)				
{
	assert(indexSprite>=0);
	assert(indexFrame>0);

	this->currentPosX=-300;
	this->currentPosY=-300;
	this->previousPosX=0;
	this->previousPosY=0;
	this->indexSprite=indexSprite;
	this->indexFrame=indexFrame;
	this->currentHealth=health;
	this->collisionCost=collisionCost;
	this->active=active;
	this->side=eSideEnemy;


	int reductionCollisionRectangleX=VIS.getFrameWidth(this->indexSprite)*10/100;
	int reductionCollisionRectangleY=VIS.getFrameHeight(this->indexSprite)*10/100;
	this->collisionRectangle.setTop(0+reductionCollisionRectangleY);
	this->collisionRectangle.setLeft(0+reductionCollisionRectangleX);
	this->collisionRectangle.setBottom(VIS.getFrameHeight(this->indexSprite)-reductionCollisionRectangleY);
	this->collisionRectangle.setRight(VIS.getFrameWidth(this->indexSprite)-reductionCollisionRectangleX);
}
CEntityEnemy::CEntityEnemy(void){}

CEntityEnemy::~CEntityEnemy(void){}

void CEntityEnemy::update(void)
{
	if(this->currentHealth<=0)
	{
		WMODEL.setNumberOfPoint(WMODEL.getNumberOfPoint()+100);
		die();
	}
	else
	{
		//if we are between time to spawn and time to time to leave
		if((int)HAPI->GetTime()>=this->timeToSpawn+WMODEL.getTimeStartLevel() 
			&& (int)HAPI->GetTime()<timeToSpawn+timeToLive+WMODEL.getTimeStartLevel())
		{
			if(this->indexNextWayPoint==-1)
			{
				initialiseDataForWayPoint();
			}
			if(reachedDestination())
			{
				goToTheNextWayPoint();
			}
			calculPosition();
			
		}
		//if it's time to leave
		else if ((int)HAPI->GetTime()>=timeToSpawn+timeToLive+WMODEL.getTimeStartLevel())
		{
			leaveScreen();
			if(currentPosY>=VIS.getScreenHeight())
			{
				this->active=false;
			}
		}

		checkCollision();
		//if a certain amount of time has passed since the the last projectile' spawn
		if(this->active && this->currentPosX>0 && this->currentPosX<VIS.getScreenWidth() &&
			this->currentPosY>0 && this->currentPosY<VIS.getScreenHeight())
		{
			shootProjectile();
		}
	}
}
void CEntityEnemy::render(void)
{
	VIS.displayFrame(this->indexSprite, this->currentPosX, this->currentPosY, this->indexFrame,true);
}

void CEntityEnemy::die(void)
{
	this->active=false;
	//spawn of an explosion
	EXPLOSIONMANAGER.spawnExplosion(EXPLOSIONMANAGER.getExplosionTemplate(eEXPLOSIONSHIP),
		this->currentPosX,this->currentPosY);
	//play sound
	SOUND.stopSound(eSoundExplosion);
	SOUND.playSound(eSoundExplosion,eVolumeHigh);
}

void CEntityEnemy::goToTheNextWayPoint(void)
{
	if(indexNextWayPoint<this->route->getNumberOfWayPoint()-1)
	{
		indexNextWayPoint++;
	}
	else
	{
		indexNextWayPoint=1;
	}
	vectorNextWayPoint=this->route->getWayPoint(indexNextWayPoint);
}

bool CEntityEnemy::reachedDestination(void)
{
	if((currentPosX>=vectorNextWayPoint.getX()-speed && currentPosX<=vectorNextWayPoint.getX()+speed )&&
		(currentPosY>=vectorNextWayPoint.getY()-speed && currentPosY<=vectorNextWayPoint.getY()+speed))
	{
		return true;
	}
	return false;
}

void CEntityEnemy::initialiseDataForWayPoint(void)
{
	this->indexNextWayPoint=1;
	this->vectorNextWayPoint=this->route->getWayPoint(indexNextWayPoint);
	currentPosX=(int)this->route->getWayPoint(0).getX();
	currentPosY=(int)this->route->getWayPoint(0).getY();
}

void CEntityEnemy::calculPosition(void)
{
	CVector2D position((float)currentPosX,(float)currentPosY);
	CVector2D direction=vectorNextWayPoint-position;
	direction.normalise();
	CVector2D offset=direction*(float)speed;

	if(offset.getX()>0 && offset.getX()<1)
	{
		offset.setX(1);
	}
	if(offset.getX()<0 && offset.getX()>-1)
	{
		offset.setX(-1);
	}
	if(offset.getY()>0 && offset.getY()<1)
	{
		offset.setY(1);
	}
	if(offset.getY()<0 && offset.getY()>-1)
	{
		offset.setY(-1);
	}
	if(offset.getX()-(int)offset.getX()>0.5)
	{
		offset.setX(offset.getX()+1);
	}
	if(offset.getY()-(int)offset.getY()>0.5)
	{
		offset.setY(offset.getY()+1);
	}
	position=position+offset;
	currentPosX=(int)position.getX();
	currentPosY=(int)position.getY();
}

void CEntityEnemy::shootProjectile(void)
{
	if(this->timeSpawnLastProjectile==-1)
	{
		this->timeSpawnLastProjectile=HAPI->GetTime();
	}
	if(this->timeSpawnLastProjectile+this->timeBetweenProjectile<(int)HAPI->GetTime())
	{
		PROJECTILEMANAGER.spawnProjectile(PROJECTILEMANAGER.getProjectileTemplate(projectileType),
			this->currentPosX,this->currentPosY);
		this->timeSpawnLastProjectile=HAPI->GetTime();
		SOUND.stopSound(eSoundEnemyShoot);
		SOUND.playSound(eSoundEnemyShoot,eVolumeLow);
	}
}

void CEntityEnemy::leaveScreen(void)
{
	CVector2D position((float)currentPosX,(float)currentPosY);
	CVector2D finalPosition((float)currentPosX,(float)VIS.getScreenHeight());
	CVector2D direction=finalPosition-position;
	direction.normalise();
	CVector2D offset=direction*(float)speed;
	
	position=position+offset;
	currentPosX=(int)position.getX();
	currentPosY=(int)position.getY();
}

void CEntityEnemy::checkCollision(void)
{
	CWorldEntity* collision=WMODEL.checkCollision(this);
	if(collision!=NULL)
	{
		this->currentHealth-=collision->getCollisionCost();
		collision->setCurrentHealth(collision->getCurrentHealth()-this->collisionCost);
		currentPosX=previousPosX;
		currentPosY=previousPosY;

		if(this->currentHealth<=0)
		{
			WMODEL.setNumberOfPoint(WMODEL.getNumberOfPoint()+100);
			die();
		}
	}
	else
	{
		this->previousPosX=this->currentPosX;
		this->previousPosY=this->currentPosY;
	}
}
void CEntityEnemy::resetEnemy(void)
{
	active=true;
	currentPosX=-300;
	currentPosY=-300;
	currentHealth=totalHealth;
	indexNextWayPoint=-1;
	switch(AI.getDifficulty())
	{
		case eDifficultyEasy:
			speed=3;
			timeBetweenProjectile=1500;
		break;
		case eDifficultyNormal:
			speed=5;
			timeBetweenProjectile=1000;
		break;
		case eDifficultyHard:
			speed=7;
			timeBetweenProjectile=500;
		break;
	}

}
int CEntityEnemy::getTotalHealth(void)
{
	return this->totalHealth;
}

void CEntityEnemy::setTimeToSpawn(int timeToSpawn)
{
	this->timeToSpawn=timeToSpawn;
}
void CEntityEnemy::setTimeToLive(int timeToLive)
{
	this->timeToLive=timeToLive;
}
void CEntityEnemy::setRoute(CRoute* route)
{
	this->route=route;
}
void CEntityEnemy::setTimeBetweenProjectile(int timeBetweenProjectile)
{
	this->timeBetweenProjectile=timeBetweenProjectile;
}
void CEntityEnemy::setIndexNextWayPoint(int indexNextWayPoint)
{
	this->indexNextWayPoint=indexNextWayPoint;
}
